/*
    TreeViewer - Cross-platform software to draw phylogenetic trees
    Copyright (C) 2023  Giorgio Bianchini, University of Bristol
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using TreeViewer;
using VectSharp;

namespace UnrootedStyleAction
{
    /// <summary>
    /// This module is used to apply to the currently opened tree the styles necessary to draw it in a "Unrooted" ("Radial")
    /// style.
    /// 
    /// The module will enable _Radial_ Coordinates module, the _Branches_ module (setting it up to draw the branches in a
    /// radial style) and the _Labels_ module, setting it up to show the labels in radial style. The current Coordinates
    /// module will be replaced, and all Plot actions will be removed.
    /// </summary>
    /// 
    /// <description>
    /// <![CDATA[
    /// ## Further information
    /// 
    /// Here is an example of a tree drawn with the style that results from applying this Action module:
    /// 
    /// <img align="center" height="800" src="" />
    /// 
    /// ]]>
    /// </description>

    public static class MyModule
    {
        public const string Name = "Unrooted tree style";
        public const string HelpText = "Sets the plot actions to display the tree as an unrooted tree.";
        public const string Author = "Giorgio Bianchini";
        public static Version Version = new Version("1.0.4");
        public const string Id = "a99eb0c6-a69d-4785-961a-a0c247e9704d";
        public const ModuleTypes ModuleType = ModuleTypes.Action;

        public static bool IsAvailableInCommandLine { get; } = true;
        public static string ButtonText { get; } = "Unrooted";
		public static List<(Avalonia.Input.Key, Avalonia.Input.KeyModifiers)> ShortcutKeys { get; } = new List<(Avalonia.Input.Key, Avalonia.Input.KeyModifiers)>() { (Avalonia.Input.Key.None, Avalonia.Input.KeyModifiers.None) };
        public static bool TriggerInTextBox { get; } = false;

        public static string GroupName { get; } = "Tree style";

        public static double GroupIndex { get; } = 2;

        public static bool IsLargeButton { get; } = false;

        public static List<(string, Func<double, VectSharp.Page>)> SubItems { get; } = new List<(string, Func<double, VectSharp.Page>)>();

        private static string Icon16Base64 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAACnSURBVDhPYxhwwAilSQZFRUUJQGo+M5Tz39LS8uHx48cvgPiEAEwzEDsygUWADCCeD5XAC5A19/X1HQC7AGjzA6ALDgKZ6/G5BF0zSAxsAAgQMgSbZhDACESgQgcgtR/CwwAomkEAxQAkzYlAhQvAglCAywVwL+DTDAIgL4G8BmSCvHgQ5GWQOCwa8WqGAWyGMBGrGQagahKBGBJOQAP+Q/03MgEDAwClc2sXcLnLmQAAAABJRU5ErkJggg==";
        private static string Icon24Base64 = "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAACiSURBVEhL7ZTRDYAgDETByWQlBmEl3EwpKQS0gBWifvB+eontHbGKmHyOxDoUrfXqigU9PCA1B2KAe7CjVMaYDTWLs7lDLShSLDayoMzhoGmAwgqwQkrmILId1BpLtGYuS+aE3OklvyJi8A7kQaglD+XdV8QxD7RmYsAT80Bt1u+gxxzA3uw/wiqWXvMAEeKRLiDcQcAj8xrZVTHafPIHhDgABgdqAudtU9YAAAAASUVORK5CYII=";
        private static string Icon32Base64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsIAAA7CARUoSoAAAADLSURBVFhH7ZVbDoUgDETRlV22xELYku7sSk0xguVRLegH56c1sTMTpaoGg7eZsHbFGPNzZYG+e4CzOdA1QGzu0EEAd8MfW22tXbEXgTIHjxkvYhYcECFlDk0cQGMFRELkzIHLGSgNcKjRIg+hRIhajeQWPAnBmc2u4Z0Q3JlsAIAQ5FAMnFrDbnz3Fdwx93BmyQBPzD21GpcAEuaeGq0ggKS5p6R5bEELcwA1gn8M1p09QCtzDxHiYGptXgKewGvmwPlL2N18MPgASm0CWppzwshXFAAAAABJRU5ErkJggg==";

        public static VectSharp.Page GetIcon(double scaling)
        {
            byte[] bytes;

            if (scaling <= 1)
            {

                bytes = Convert.FromBase64String(Icon16Base64);
            }
            else if (scaling <= 1.5)
            {
                bytes = Convert.FromBase64String(Icon24Base64);
            }
            else
            {
                bytes = Convert.FromBase64String(Icon32Base64);
            }

            IntPtr imagePtr = Marshal.AllocHGlobal(bytes.Length);
            Marshal.Copy(bytes, 0, imagePtr, bytes.Length);

            VectSharp.RasterImage icon;

            try
            {
                icon = new VectSharp.MuPDFUtils.RasterImageStream(imagePtr, bytes.Length, MuPDFCore.InputFileTypes.PNG);
            }
            catch (Exception ex)
            {
                throw ex.InnerException;
            }
            finally
            {
                Marshal.FreeHGlobal(imagePtr);
            }

            VectSharp.Page pag = new VectSharp.Page(16, 16);
            pag.Graphics.DrawRasterImage(0, 0, 16, 16, icon);

            return pag;
        }

        public static void PerformAction(int actionIndex, MainWindow window, InstanceStateData stateData)
        {
            if (stateData.Trees != null)
            {
                int branches = 0;
                int labelName = 0;
                int labelLength = 0;
                int other = 0;

                List<PlottingModule> plottingModules = stateData.PlottingModules();

                for (int i = 0; i < plottingModules.Count; i++)
                {
                    if (plottingModules[i].Id == "7c767b07-71be-48b2-8753-b27f3e973570")
                    {
                        branches++;
                    }
                    else if (plottingModules[i].Id == "ac496677-2650-4d92-8646-0812918bab03")
                    {
                        string labelAttribute = (string)stateData.GetPlottingModulesParameters(i)["Attribute:"];

                        if (labelAttribute == "Name")
                        {
                            labelName++;
                        }
                        else if (labelAttribute == "Length")
                        {
                            labelLength++;
                        }
                        else
                        {
                            other++;
                        }
                    }
                    else
                    {
                        other++;
                    }
                }

                if (InstanceStateData.IsUIAvailable)
				{
					Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(async () =>
					{
						if (branches > 1 || labelName > 1 || labelLength > 1 || other > 0)
						{
							MessageBox box = new MessageBox("Question", "It looks like you have made some changes to the plot. Please note that if you use this module, those changes may be lost.\nIf you wish to keep your changes, use the \"Reshape tree\" action instead.\nDo you wish to proceed anyways?", MessageBox.MessageBoxButtonTypes.YesNo);

							await box.ShowDialog2(window);

							if (box.Result == MessageBox.Results.No)
							{
								return;
							}
						}
						
						window.PushUndoFrame(UndoFrameLevel.CoordinatesModule, 0);

						while (stateData.PlottingModules().Count > 0)
						{
							stateData.RemovePlottingModule(0);
						}
						Action<Dictionary<string, object>> updater = stateData.AddPlottingModule(Modules.GetModule(Modules.PlottingModules, "7c767b07-71be-48b2-8753-b27f3e973570"));
						updater(new Dictionary<string, object>() { { "Root branch", false } });

						updater = stateData.AddPlottingModule(Modules.GetModule(Modules.PlottingModules, "ac496677-2650-4d92-8646-0812918bab03"));
						updater(new Dictionary<string, object>() { { "Reference:", 1 } });

						double defaultHeight = Math.Min(10000, stateData.TransformedTree.GetLeaves().Count * 14);

						CoordinateModule module = Modules.GetModule(Modules.CoordinateModules, "95b61284-b870-48b9-b51c-3276f7d89df1");

						updater = stateData.SetCoordinatesModule(module);
						updater(new Dictionary<string, object>() { { "Width:", defaultHeight }, { "Height:", defaultHeight }, { "Apply", true } });

						window.AutoFit();
					});
				}
				else
				{
					while (stateData.PlottingModules().Count > 0)
					{
						stateData.RemovePlottingModule(0);
					}
					Action<Dictionary<string, object>> updater = stateData.AddPlottingModule(Modules.GetModule(Modules.PlottingModules, "7c767b07-71be-48b2-8753-b27f3e973570"));
					updater(new Dictionary<string, object>() { { "Root branch", false } });

					updater = stateData.AddPlottingModule(Modules.GetModule(Modules.PlottingModules, "ac496677-2650-4d92-8646-0812918bab03"));
					updater(new Dictionary<string, object>() { { "Reference:", 1 } });

					double defaultHeight = Math.Min(10000, stateData.TransformedTree.GetLeaves().Count * 14);

					CoordinateModule module = Modules.GetModule(Modules.CoordinateModules, "95b61284-b870-48b9-b51c-3276f7d89df1");

					updater = stateData.SetCoordinatesModule(module);
					updater(new Dictionary<string, object>() { { "Width:", defaultHeight }, { "Height:", defaultHeight }, { "Apply", true } });
				}
            }
        }
    }
}